<?php

namespace Melo\ConfigSync;

class Sync {

    private $isAlive = true;

    private $signalRegistered = false;

    public function __construct()
    {
        $this->registerSignalIfNecessary();
    }

    /**
     * 读取apollo配置
     * @param null $callback
     */
    public function run()
    {
        $clientIp = $this->getClientIp();
        $syncOnce = $this->syncOnce();
        $cluster = $this->getCluster();
        echo 'cluster is:' . $cluster;
        echo 'save_path is :' . $this->getSavePath() . "\r\n";
        echo 'config server is :' . $this->getConfigServer() . "\r\n";
        echo 'app_id is :' . $this->getAppId() . "\r\n";
        echo 'namespaces is :' . implode(',', $this->getNamespaces()) . "\r\n";
        echo "client ip is :" . $clientIp . "\r\n";
        echo "sync once is:" . ($syncOnce ? 'true' : 'false')  . "\r\n";
        $apollo = new ApolloClient($this->getConfigServer(), $this->getAppId(), $this->getNamespaces());

        if ($clientIp) {
            $apollo->setClientIp($clientIp);
        }
        if ($cluster) {
            $apollo->setCluster($cluster);
        }
        $apollo->save_dir = $this->getSavePath();
        ini_set('memory_limit', '128M');
        $pid = getmypid();
        echo "start [$pid]\r\n";
        do {
            $error = $apollo->start();
            if ('success' == $error) {
                echo "get config success\r\n";
                if ($syncOnce) {
                    echo "sync once success, exit \r\n";
                    return;
                }
            } 
            echo('warning:' . $error . "\r\n");
            echo "restarting apollo config client daemon\r\n";
            
            $this->registerSignalIfNecessary();
            sleep(5);
        } while ($this->isAlive);
    }
    
    public function getCluster()
    {
        return getenv('APOLLO_CLUSTER');
    }

    /**
     * @return mixed
     */
    public function getClientIp()
    {
        return gethostbyname(trim(exec("hostname")));
    }

    /**
     * @return mixed
     */
    public function getNamespaces()
    {
        return explode(",", getenv('APOLLO_NAMESPACES'));
    }

    /**
     * @return mixed
     */
    public function getAppId()
    {
        return getenv('APOLLO_APP_ID');
    }


    /**
     * @return mixed
     */
    public function getConfigServer()
    {
        return getenv('APOLLO_CONFIG_SERVER');
    }

    public function syncOnce() : bool
    {
        $syncOnce = getenv('APOLLO_SYNC_ONCE');
        return ($syncOnce === false || $syncOnce === 'false') ? false : true;
    }


    /**
     * @return mixed
     */
    public function getSavePath()
    {
        $savePath = getenv('APOLLO_SAVE_PATH');
        if (empty($savePath)) {
            $savePath = '/home/config/' . $this->getAppId();
        }
        if (!is_dir($savePath)) {
            mkdir($savePath, 0777, true);
        }
        return $savePath;
    }

    protected function registerSignalIfNecessary()
    {
        if (!$this->signalRegistered) {
            $this->registerSignal();
            $this->signalRegistered = true;
        }
        if (function_exists('pcntl_signal_dispatch')) {
            pcntl_signal_dispatch();
        }
    }

    public function signalHandler($signo, $pid = null, $status = null)
    {
        switch ($signo) {
            case SIGHUP:
            case SIGTERM:
            case SIGINT:
            case SIGTSTP:
                echo "get quit signal,quit now \r\n";
                $this->stop($signo);
                return;
            default:
                echo "get a signal with no handler" . $signo . "\r\n"; 
                // 处理所有其他信号
        }
    }

    protected function registerSignal()
    {
        if (function_exists('pcntl_signal')) {
            echo 'pcntl_signal' . PHP_EOL;
            pcntl_signal(SIGINT, [$this, 'signalHandler']);
            pcntl_signal(SIGTERM, [$this, 'signalHandler']);
            pcntl_signal(SIGHUP, [$this, 'signalHandler']);
            pcntl_signal(SIGTSTP, [$this, 'signalHandler']);
        }
    }

    /**
     * @param int $signal
     *
     */
    final protected function stop(int $signal = 0): void
    {
        $this->isAlive = false;
        return;
    }
}